-
Notifications
You must be signed in to change notification settings - Fork 4
Feature/launch at login #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/launch at login #2
Conversation
Add ability to detect and display listening ports for running services using lsof.
Features:
- Detect TCP/UDP listening ports for services and their child processes
- Display ports in service info panel with protocol and port number
- Show port summary in service actions popover (first 3 ports)
- Automatically detect child processes to catch ports from worker processes
Implementation:
- PortDetector actor uses lsof to find listening ports by PID
- Recursively finds all descendant PIDs to include child process ports
- ServicePort model represents detected ports with protocol type
- Ports displayed in both detail panel and popover menu
Technical details:
- Uses `lsof -nP -iTCP -sTCP:LISTEN -a -p {pids}` for detection
- Uses `ps -o pid= -g {pid}` to find child processes
- Port detection is non-blocking and gracefully handles errors
- No thousands separators in port number display
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add ability to configure custom URLs for each service with auto-detection based on detected ports. Features: - Configure custom URLs per service (e.g., http://localhost:8384 for Syncthing) - Auto-suggest URLs based on detected listening ports - Display links as inline icon buttons in service rows (up to 2 visible) - Full link management UI with add/edit/delete functionality - Persistent storage across app restarts - Service-agnostic design (no hardcoded service-specific URLs) Implementation: - ServiceLinksStore manages links with JSON persistence to Application Support - Links displayed inline in service rows and in popover menu - ServiceLinksManagementView provides full CRUD interface - Smart URL suggestions for common HTTP/HTTPS ports - Opens links in default browser via NSWorkspace Technical details: - Uses @observable pattern for reactive state management - Persists to ~/Library/Application Support/BrewServicesManager/{bundleId}/service-links.json - Inline overlay-based forms (avoids .sheet() issues in menu bar extras) - Supports multiple links per service with optional custom labels - Auto-focuses text fields for better UX 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Improve visual consistency in the popover header section: - Use consistent spacing for all HStack elements in header - Align status and port information properly with action icons - Match line heights between header section and menu items Changes: - Change VStack spacing from tightSpacing to compactSpacing for better vertical rhythm - Add explicit tightSpacing to status and operation HStacks - Ensures network icon and status icon align consistently 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Fix system authentication dialog interaction issue in MenuBarExtra context. Problem: When switching to system domain or performing privileged operations, the osascript authentication dialog appears but cannot receive mouse clicks because the MenuBarExtra interferes with input handling. Solution: Call NSApp.activate(ignoringOtherApps: true) before showing the authentication dialog. This brings the app to the foreground and ensures the system dialog can properly receive user input. Changes: - Import AppKit in PrivilegeEscalator - Add NSApp.activate() call on MainActor before executing osascript - Dialog now properly accepts clicks and keyboard input This complements the earlier fix for SwiftUI dialogs (using inline overlays instead of .sheet()) to fully resolve dialog interaction issues in menu bar extras. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Replaces command-line osascript with NSAppleScript API running on MainActor. This fixes the issue where the system authentication dialog could not be interacted with using the mouse in MenuBarExtra apps. The previous approach of activating the app didn't work because osascript ran as a separate process, causing focus issues. NSAppleScript executes in-process on the main thread, properly associating the auth dialog with the app's event loop. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Adds comprehensive documentation for the new features: - Port detection: automatic discovery of listening ports - Service links: user-configurable URLs for web interfaces - Troubleshooting section for port detection issues - Documentation for the authentication dialog fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Removes hardcoded DEVELOPMENT_TEAM settings to allow contributors to use their own Apple Developer accounts. Contributors will need to select their team in Xcode's Signing & Capabilities editor when building. This is standard practice for open source macOS projects. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Adds clear instructions for configuring code signing after removing hardcoded development team IDs. Documents the requirement for an Apple Developer account and provides step-by-step setup instructions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Fix data race in ServiceLinksStore save() method - Fix child process detection using pgrep instead of ps -g - Improve URL validation with blacklist approach - Simplify redundant port range logic - Make detectedPorts immutable in BrewServiceInfoEntry - Fix misleading PostgreSQL example in README - Remove thousands separator from port suggestions Addresses feedback from Copilot PR review on: - Data race concerns with Swift concurrency - Incorrect ps command semantics - Security concerns with URL validation - Code quality improvements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove thousands separators from port numbers in UI - Trigger port detection when actions popover opens - Ensure ports appear immediately without requiring View Info click Port numbers now display without locale formatting (8080 not 8,080) and are detected eagerly when user opens the actions menu. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
|
You're amazing thank you! I'll check this PR tomorrow |
|
@alexbartok could you please resolve the conflict? so I'll review after that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds launch-at-login functionality using the modern SMAppService API from ServiceManagement, along with two additional features: automatic port detection for running services and user-configurable service links for quick access to web interfaces.
Key Changes:
- Launch-at-login support with UserDefaults persistence and system state synchronization
- Port detection using
lsofto identify listening ports for services and their child processes - Service links management for storing and accessing custom URLs per service
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
LaunchAtLoginError.swift |
New error type for launch-at-login failures with localized descriptions |
BrewServicesManager.entitlements |
Minimal entitlements configuration (no app sandbox to preserve Homebrew access) |
AppSettings.swift |
Launch-at-login state management with UserDefaults and SMAppService integration |
SettingsView.swift |
UI for launch-at-login toggle with inline error display |
AppKitBridge.swift |
Added URL opening helper method for consistency |
project.pbxproj |
Code signing configuration and development team setup |
README.md |
Updated documentation for new features and build requirements |
ServicePort.swift |
New model for representing listening ports with protocol information |
PortDetector.swift |
Port detection using lsof with child process support |
ServiceLinksStore.swift |
Persistent storage for user-configured service links |
ServiceLink.swift |
Model for user-configured service URLs |
ServiceLinksManagementView.swift |
UI for managing service links with validation |
ServicesStore.swift |
Added port detection integration |
BrewServiceInfoEntry.swift |
Added runtime-only detectedPorts property |
ServiceInfoView.swift |
Display detected ports in service info |
ServiceActionsPopoverView.swift |
Show port summary and links in popover |
ServiceMenuItemView.swift |
Display service links inline |
MenuBarRootView.swift |
Added links management overlay |
MainMenuServicesSectionView.swift |
Wired up links management callback |
MainMenuContentView.swift |
Passed through links management handler |
BrewServicesManagerApp.swift |
Added ServiceLinksStore to environment |
PrivilegeEscalator.swift |
Switched to NSAppleScript for better dialog control |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ac309fa to
7528e26
Compare
Removes hardcoded DEVELOPMENT_TEAM from project.pbxproj and uses gitignored xcconfig files instead. This keeps the repo clean while allowing contributors to easily configure their own team ID. Contributors now copy Development.shared.xcconfig to Development.xcconfig and set their team ID there. Also removes 'file' from blockedSchemes to allow legitimate file:// URLs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Adds the ability to automatically start the app when the user logs in to macOS, using the modern SMAppService API from ServiceManagement framework. Changes: - Add LaunchAtLoginError.swift for error handling - Extend AppSettings with launch-at-login state management and system synchronization - Update SettingsView with toggle UI and inline error display - Add entitlements file (without app sandbox to preserve Homebrew access) - Configure CODE_SIGN_ENTITLEMENTS in Xcode project - Update README with new feature documentation The implementation: - Syncs with system state on app launch to handle manual changes - Handles errors gracefully with user-friendly messages - Provides direct link to System Settings when approval is needed - Works without requiring full app sandboxing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove didSet trigger in AppSettings to prevent redundant API calls - Remove 'file' from blockedSchemes to allow legitimate file:// URLs - Implement xcconfig-based team configuration for clean repo Addresses review comments from GitHub Copilot PR review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Remove didSet triggers in syncLaunchAtLoginState to prevent infinite loops - Use AppKitBridge.openURL for consistency instead of NSWorkspace Addresses additional review comments from GitHub Copilot. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
b0c31a4 to
ab9e4c1
Compare
|
Thanks for the fixes, but the PR still has merge conflicts. Could you have a chance to resolve these also? |
Resolves merge conflicts by: - Accepting upstream's refactored architecture (enum-based routing, view separation) - Accepting upstream's improved port detection and service links implementation - Accepting upstream's Sparkle auto-update integration (v1.1.3) - Preserving launch-at-login functionality with ServiceManagement - Preserving xcconfig-based team configuration - Combining Settings UI for both updates and launch-at-login - Adopting upstream's actor isolation improvements (nonisolated annotations) - Using continuation pattern for privilege escalation dialog handling Key changes: - BrewServicesManagerApp: Restored AppUpdater state and badge logic - AppSettings: Merged automaticallyCheckForUpdates + launchAtLogin properties - SettingsView: Combined Launch, Updates, and About sections - PrivilegeEscalator: nonisolated enum with withCheckedThrowingContinuation pattern - AppKitBridge: Removed @mainactor, added openURL method - project.pbxproj: Added xcconfig, removed hardcoded DEVELOPMENT_TEAM - README: Updated with xcconfig setup instructions Version: 1.1.3 (build 7) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
|
Here you go! |
|
LGTM! |
Sorry, one more while I'm at it ;-)
Add Launch at Login Functionality
Summary
Adds the ability to automatically start BrewServicesManager when the user logs in to macOS. This feature uses the modern
SMAppServiceAPI from the ServiceManagement framework, providing a native and reliable launch-at-login experience.Changes
New Files
LaunchAtLoginError.swift- Error type for handling launch-at-login failures with localized descriptions and recovery suggestionsBrewServicesManager.entitlements- Entitlements file for code signing with documentation explaining why app sandbox is disabled to preserve Homebrew accessModified Files
AppSettings.swift- Added launch-at-login state management with:SMAppServiceSettingsView.swift- Added new "Launch" settings card with:project.pbxproj- ConfiguredCODE_SIGN_ENTITLEMENTSfor both Debug and Release buildsproject.pbxproj- Updated deployment target to 15.0 (from 15.7) and configuredCODE_SIGN_ENTITLEMENTSfor both Debug and Release buildsREADME.md- Updated feature list and settings documentationImplementation Details
Architecture
The implementation follows existing patterns in the codebase:
AppSettings(@observable class) rather than creating a separate managerdidSetobservers for automatic updatesKey Features
Technical Decisions
Why No App Sandbox?
Initially implemented with full app sandboxing (as commonly recommended for ServiceManagement), but this broke Homebrew detection and command execution. Testing revealed that
SMAppServiceworks perfectly without app sandboxing on modern macOS. The entitlements file includes only the minimalcom.apple.application-identifierkey, with XML comments documenting why sandboxing is disabled (to preserve shell access for Homebrew commands, sudo privilege escalation, and lsof port detection).Error State Handling
.notFoundstatus (which occurs when running from Xcode or when not yet registered) is treated as a normal state rather than an error, preventing unnecessary error messages on first launch.Testing
Manual Testing Checklist
Notes